<?php

declare (strict_types=1);

namespace magein\pay\platform;

use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\EasySDKKernel;
use Alipay\EasySDK\Kernel\Factory;

use magein\pay\data\NoticeData;
use magein\pay\data\PayOrderData;
use magein\pay\extension\AliSdkPage;
use magein\pay\PayConfig;
use magein\pay\PayException;
use magein\pay\PayFactory;
use magein\pay\PayPlatform;
use magein\utils\Result;

class AliPay extends PayPlatform
{

    // 手机网站支付产品
    const TRADE_TYPE_WAP = 'QUICK_WAP_WAY';

    // 电脑支付场景
    const TRADE_TYPE_FAST = 'FAST_INSTANT_TRADE_PAY';

    /**
     * @var EasySDKKernel|null
     */
    private $kernel = null;

    public static function getPlatformName(): string
    {
        return 'ali';
    }

    /**
     * @param $data
     * @return array
     */
    public function matchConfig($data): array
    {

        $merchant_id = $data['merchant_id'] ?? '';
        $merchant_id = $merchant_id ?: ($data['appid'] ?? '');

        // 收款账号配置
        $accounts = PayConfig::platformAccount(self::getPlatformName());

        $config = [];
        if ($accounts && is_array($accounts)) {
            foreach ($accounts as $account) {
                if ($account['appid'] == $merchant_id) {
                    $config = $account;
                    break;
                }
            }
        }

        return $config;
    }

    /**
     * @param array $config
     * @return EasySDKKernel
     */
    public function init(array $config = []): EasySDKKernel
    {
        $options = new Config();
        $options->protocol = 'https';
        $options->gatewayHost = 'openapi.alipay.com';
        $options->signType = 'RSA2';
        $options->appId = $config['appid'] ?? '';

        // 公钥字符串
        $options->merchantPrivateKey = $config['merchant_private_key'] ?? '';
        $options->alipayPublicKey = $config['platform_public_key'] ?? '';
        $options->encryptKey = $config['encrypt_key'] ?? '';

        // 公钥证书的方式
        $certs = $config['certs'] ?? [];
        if ($certs) {
            $options->alipayCertPath = $certs['cert_public'] ?? '';
            $options->alipayRootCertPath = $certs['cert_root'] ?? '';
            $options->merchantCertPath = $certs['cert_merchant'] ?? '';
        }

        Factory::setOptions($options);

        $this->kernel = new EasySDKKernel($options);

        return $this->kernel;
    }

    /**
     * 统一下单
     * @param PayOrderData $pay_order_data
     * @return Result
     */
    public function unify(PayOrderData $pay_order_data): Result
    {
        try {

            PayFactory::order()->create($pay_order_data);

            if ($pay_order_data->getTradeType() == self::TRADE_TYPE_FAST) {
                $result = (new AliSdkPage($this->kernel))->asyncNotify(
                    $this->getNotifyUrl($pay_order_data->getPayNo()))
                    ->pay($pay_order_data->getSubject(),
                        $pay_order_data->getPayNo(),
                        $pay_order_data->getTotalAmount(),
                        $this->getSuccessUrl($pay_order_data->getPayNo())
                    );

                return Result::success($result);

            } else {
                $result = Factory::payment()->wap()->asyncNotify(
                    $this->getNotifyUrl($pay_order_data->getPayNo())
                )->pay(
                    $pay_order_data->getSubject(),
                    $pay_order_data->getPayNo(),
                    $pay_order_data->getTotalAmount() / 100,
                    $this->getQuiteUrl($pay_order_data->getPayNo()),
                    $this->getSuccessUrl($pay_order_data->getPayNo())
                );
                // body是一个form表单代码
                if ($result->body) {
                    return Result::success($result->body);
                } else {
                    return Result::error('创建支付信息错误');
                }
            }
        } catch (PayException $exception) {
            $result = $exception->toResult();
        } catch (\Exception $e) {
            $result = Result::error($e->getMessage());
        }

        return $result;
    }

    public function queryByPayNo($pay_no)
    {
        try {
            $result = Factory::payment()->common()->query($pay_no)->toMap();
        } catch (\Exception $exception) {
            $result = null;
        }

        return $result;
    }

    /**
     * 异步通知验签
     * @param $data
     * @return bool
     */
    protected function verifyNotify($data): bool
    {
        return Factory::payment()->common()->verifyNotify($data);
    }

    public function notifyData($data): NoticeData
    {
        $notify = new NoticeData();
        $notify->setPayNo($data['out_trade_no'] ?? '');
        $notify->setTradeNo($data['trade_no'] ?? '');
        $notify->setNotifyData($data);
        $notify->setNotifyDate($data['gmt_create'] ?? '');
        if (($data['trade_status'] ?? '') == 'TRADE_SUCCESS') {
            $notify->success();
        } else {
            $notify->fail();
        }
        return $notify;
    }

    /**
     * @param $data
     * @return NoticeData
     */
    public function handleNotify($data): NoticeData
    {
        $notify = $this->notifyData($data);

        if (!is_local() && !$this->verifyNotify($data)) {
            $notify->fail('效验签名失败');
            $notify->setOk(false);
        }

        $notify->setResponse('success');

        return $notify;
    }
}